import { PlusOutlined, SyncOutlined, SearchOutlined, MenuOutlined } from '@ant-design/icons'
import { css } from '@emotion/react'
import { keywordCompare } from '@gnlab/utils'
import { useBoolean } from '@gnlab/utils/env-react'
import { Button, Tag, message, Input } from 'antd'
import AutoSizer from 'react-virtualized-auto-sizer'
import { FixedSizeList as List } from 'react-window'
import { Actionable, EditModal, AvatarImage } from '@/desktop/components'
import BeautyMenu from '@/desktop/components/BeautyMenu'
import type { MenuItem } from '@/desktop/components/BeautyMenu'
import ChooseContacts from '@/desktop/components/ChooseContacts'
import  defaultAvatar  from '@/desktop/assets/avatar.jpg'
import { triggerAt } from '@/desktop/views/chat/editor/at-members'
import { useStreams } from '@/lib/utils'
import services from '@/services'
import type { GroupContact } from '@/services/contact-types/groups'
import { ContactType, type BaseContact } from '@/services/contacts'
import './index.module.less'

export default function GroupMembers() {
  const [contact] = useStreams(services.contacts.current.contact)
  return contact?.type === ContactType.group ? <Content group={contact} /> : null
}

function Content(props: { group: GroupContact }) {
  const { group } = props
  const [members] = useStreams(services.groups.members)
  const sortedMembers = useMemo(
    () =>
      [...members].sort((a, b) =>
        group.creatorWxid === a.userId ? -1 : group.creatorWxid === b.userId ? 1 : 0,
      ),
    [members, group],
  )

  const [search, setSearch] = useState('')
  const filterSortedMembers = useMemo(() => {
    return search ? sortedMembers.filter(v => keywordCompare(search, v.name)) : sortedMembers
  }, [search, sortedMembers])

  const chooseContactTypes = useMemo(
    () =>
      // 外部群不支持拉“客户”进群
      group.isExternal ? [ContactType.internal, ContactType.external] : [ContactType.internal],
    [group],
  )
  const [adding, startAdd, finishAdd] = useBoolean(false)
  const executeAdd = useCallback(
    async (choosed: BaseContact[]) => {
      const res = (await services.groups.addMembers(choosed.map(v => v.userId)))!
      if (res.success) {
        void message.success('群成员添加成功')
        finishAdd()
      } else {
        void message.warning(`群成员添加失败：${res.error}`)
      }
    },
    [finishAdd],
  )

  const [applying, setApplying] = useState<BaseContact | null>(null)

  const renderMember = useMemo(
    () =>
      Member.bind(null, {
        group,
        applyMember: setApplying,
      }),
    [group],
  )

  return <div styleName="group-members-panel">
    <div styleName="actions">
      <Actionable>
        <Button size="small" icon={<PlusOutlined />} onClick={startAdd}>
          添加成员
        </Button>
      </Actionable>
      <Button
        size="small"
        icon={<SyncOutlined />}
        onClick={async () => services.groups.loadMembers()}
      >
        刷新
      </Button>
    </div>

    <div styleName="search">
      <Input
        prefix={<SearchOutlined />}
        value={search}
        onChange={e => setSearch(e.target.value)}
        placeholder="搜索群成员"
      />
    </div>

    <div styleName="members">
      <AutoSizer>
        {({ height, width }) => <List
          height={height}
          width={width}
          itemCount={filterSortedMembers.length}
          itemData={filterSortedMembers}
          itemKey={getItemKey}
          itemSize={56}
        >
          {renderMember}
        </List>}
      </AutoSizer>
    </div>

    <ChooseContacts
      visible={adding}
      title="添加群成员"
      ownerWxid={group.ownerWxid}
      types={chooseContactTypes}
      disabledWxids={members.map(v => v.userId)}
      onCancel={finishAdd}
      onFinish={executeAdd}
    />
    <ApplyModal member={applying} onClose={() => setApplying(null)} />
  </div>
}

function getItemKey(index: number, data: BaseContact[]) {
  return data[index]!.id
}

function Member(
  globalProps: {
    group: GroupContact
    applyMember: (member: BaseContact) => void
  },
  props: {
    index: number
    data: BaseContact[]
    style: React.CSSProperties
  },
) {
  const { group, applyMember } = globalProps
  const { index, data, style } = props
  const member = data[index]!
  const isOwner = group.creatorWxid === member.userId

  const isSelf = member.userId === group.ownerWxid
  // 是否可加好友（不是现有客户、不是同一公司的员工、不是自己）
  const [applyAble, setApplyAble] = useState<boolean | null>(isSelf ? false : null)
  // 是否是联系人（只要能出现在联系人列表就算，例如被删了也算）
  const [isContact, setIsContact] = useState<boolean | null>(isSelf ? false : null)
  // 每次开启菜单时确认一次联系人状态
  async function handleMenuOpen(open: boolean) {
    if (!open) return
    let contact = services.contacts.getById(member.id)
    if (!contact) {
      await services.contacts.loadInfo({ id: member.id })
      contact = services.contacts.getById(member.id)
    }
    setApplyAble(!contact || (contact.type === ContactType.external && contact.deleted !== null))
    setIsContact(!!contact)
  }

  const menuItems = [
    {
      title: '@群成员',
      onClick() {
        triggerAt(member)
      },
    },
    applyAble === true
      ? {
          title: '加好友',
          onClick: () => applyMember(member),
        }
      : null,
    isContact === true
      ? {
          title: '进入聊天',
          onClick: () => services.contacts.current.mark(member.id),
        }
      : null,
    member.userId !== group.ownerWxid && member.userId !== group.ownerWxid
      ? {
          title: '移出群聊',
          onClick: async () => {
            const res = await services.groups.removeMember([member.userId])
            if (res?.success === true) void message.success('已移出群聊')
            else void message.error('移出群聊失败：' + (res?.error ?? ''))
          },
        }
      : null,
  ].filter(v => v !== null) as MenuItem[]

  return <div style={style} styleName="member">
    <AvatarImage size={40} radius={4} src={member.avatar || defaultAvatar} />
    <div styleName="name">
      <span styleName="txt" onClick={() => triggerAt(member)}>
        {member.remark || member.name}
      </span>
      {isOwner ? (
        <span styleName="extra">
          <Tag>群主</Tag>
        </span>
      ) : null}
    </div>
    {menuItems.length ? (
      <BeautyMenu items={menuItems} onOpenChange={handleMenuOpen}>
        <MenuOutlined />
      </BeautyMenu>
    ) : null}
  </div>
}

function ApplyModal({ member, onClose }: { member: BaseContact | null; onClose: () => void }) {
  return <EditModal title="添加好友" open={member !== null} onCancel={onClose}>
    {member !== null ? <ApplyContent member={member} onClose={onClose} /> : null}
  </EditModal>
}

function ApplyContent({ member, onClose }: { member: BaseContact; onClose: () => void }) {
  const [verifyMessage, setVerifyMessage] = useState('')
  const [submitting, setSubmitting] = useState(false)
  async function submit() {
    setSubmitting(true)
    const res = await services.groups.applyMember(member.userId, verifyMessage)
    setSubmitting(false)
    if (res?.success === true) {
      void message.success('已发送申请')
      onClose()
    } else {
      void message.error('申请发送失败：' + (res?.error ?? ''))
    }
  }

  return <main>
    <div css={styles.info}>
      <img src={member.avatar || defaultAvatar} />
      <span>{member.name}</span>
    </div>
    <div css={styles.message}>
      <Input.TextArea
        value={verifyMessage}
        onChange={e => setVerifyMessage(e.target.value)}
        placeholder="输入验证消息"
        rows={5}
      />
    </div>
    <div css={styles.submit}>
      <Button type="primary" onClick={submit} loading={submitting}>
        发送申请
      </Button>
    </div>
  </main>
}

const styles = {
  info: css`
    display: flex;
    align-items: center;
    column-gap: 12px;
    img {
      width: 45px;
      height: 45px;
      border-radius: 4px;
    }
  `,
  message: css`
    border-top: 1px solid #f0f0f0;
    margin-top: 20px;
  `,
  submit: css`
    padding-top: 20px;
    text-align: right;
  `,
}
